package com.feemanage.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.common.api.ApprovalApi;
import com.common.core.domain.entity.SysUser;
import com.common.core.page.PageDomain;
import com.common.utils.CurrentRoleUtils;
import com.common.utils.SecurityUtils;
import com.common.utils.bean.BizProcessMessages;
import com.common.utils.sql.SqlUtil;
import com.feemanage.common.SearchUtils;
import com.feemanage.domain.*;
import com.feemanage.domain.bo.FundsFeeShowBo;
import com.feemanage.domain.vo.*;
import com.feemanage.mapper.*;
import com.feemanage.service.IBizBudgetAlterationService;
import com.feemanage.service.IBizBudgetAmountAlterationService;
import com.feemanage.service.IcWIncomeService;
import com.flowable.domain.vo.task.BpmTaskApproveReqVO;
import com.flowable.service.IFlowTaskService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service("biz_budget_alteration")
public class BizBudgetAlterationServiceImpl implements IBizBudgetAlterationService {

    @Autowired
    private bizBudgetAlterationMapper baseMapper;

    @Autowired
    private bizFeeCardAlterationMapper feeCardMapper;

    @Autowired
    private IBizBudgetAmountAlterationService amountService;

    @Autowired
    private bizBudgetAmountAlterationMapper amountMapper;

    @Autowired
    private bizProjectIncomeMapper incomeMapper;

    @Autowired
    private bizProjectFeeCardBudgetMapper budgetMapper;

    @Autowired
    private cWIncomeClaimMapper claimMapper;

    @Autowired
    private IcWIncomeService incomeService;

    @Autowired
    private ApprovalApi approvalApi; //发起流程

    @Autowired
    private IFlowTaskService flowTaskService;//流程引擎

    private final static String project_Class_yF="yfContract"; // 横向项目

    private  final static  String modelName="经费调账";
    /**
     * 查询列表
     * @param pageDomain
     * @param alteration
     * @return
     */
    @Override
    public IPage<BizBudegtAlterationVo> selectList(PageDomain pageDomain, BizBudgetAlteration alteration) {
        Page<BizBudegtAlterationVo> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
        QueryWrapper<BizBudgetAlteration> wrapper = getQuery(alteration);
        String orderByColumn = SqlUtil.escapeOrderBySql(pageDomain.getOrderByColumn());
        boolean isASC = SqlUtil.escapeOrderBySql(pageDomain.getIsAsc()).equalsIgnoreCase("asc");
        if (!StringUtils.isEmpty(orderByColumn))
        {
            wrapper.orderBy(true,isASC,orderByColumn);
        }
        IPage<BizBudegtAlterationVo> list = baseMapper.selectPageList(page,wrapper);
        // 获取流程任务列表,Map<instanceId, taskId>
        Map<String, String> instanceTaskMap = approvalApi.getInstanceTaskMap(modelName);

        for (BizBudegtAlterationVo u : list.getRecords()) {
            // 判断是否是审核人，并设置taskId
            String processInstanceId = u.getProcessInstanceId();
            if (com.common.utils.StringUtils.isNotEmpty(processInstanceId) && instanceTaskMap.containsKey(processInstanceId)) {
                u.setTaskId(instanceTaskMap.get(processInstanceId));
                u.setIsAuditor(true);
            } else {
                u.setIsAuditor(false);
            }
        }
        return list;
    }


    /**
     * 统计检索
     * @param alteration
     * @return
     */
    @Override
    public List<HashMap<String, Integer>> selectListTotal(BizBudgetAlteration alteration){
        QueryWrapper<BizBudgetAlteration> wrapper = getQuery(alteration);
        return baseMapper.selectListTotal(wrapper);
    }

    /**
     * 导出
     * @param alteration
     * @return
     */
    @Override
    public List<BizBudegtAlterationVo> selectExportList(PageDomain pageDomain,BizBudgetAlteration alteration) {
        QueryWrapper<BizBudgetAlteration> wrapper = getQuery(alteration);
        String orderByColumn = SqlUtil.escapeOrderBySql(pageDomain.getOrderByColumn());
        boolean isASC = SqlUtil.escapeOrderBySql(pageDomain.getIsAsc()).equalsIgnoreCase("asc");
        if (!StringUtils.isEmpty(orderByColumn))
        {
            wrapper.orderBy(true,isASC,orderByColumn);
        }
        return baseMapper.selectPageList(wrapper);
    }


    /**
     * 拼接条件
     * @param alteration
     * @return
     */
    public QueryWrapper<BizBudgetAlteration> getQuery(BizBudgetAlteration alteration){
        Map<String, Object> params = alteration.getParams();
        QueryWrapper<BizBudgetAlteration> wrapper = Wrappers.query();
        wrapper.eq(StringUtils.isNotEmpty(alteration.getProjectId()),"p.id",alteration.getProjectId())
                .eq(StringUtils.isNotBlank(alteration.getId()),"b.id",alteration.getId())
                .like(StringUtils.isNotBlank(alteration.getProjectName()), "p.name", alteration.getProjectName())
                .like(StringUtils.isNotBlank(alteration.getChargerName()),"p.charger_name",alteration.getChargerName())
                .between(ObjectUtils.isNotEmpty(params.get("beginTime")) && ObjectUtils.isNotEmpty(params.get("endTime")),
                        "b.alterdate", params.get("beginTime"), params.get("endTime"))
                .ge(ObjectUtils.isNotEmpty(params.get("beginTime")) && ObjectUtils.isEmpty(params.get("endTime")),"b.alterdate", params.get("beginTime"))
                .le(ObjectUtils.isEmpty(params.get("beginTime")) && ObjectUtils.isNotEmpty(params.get("endTime")),"b.alterdate", params.get("endTime"))
                .between(ObjectUtils.isNotEmpty(params.get("beginDate")) && ObjectUtils.isNotEmpty(params.get("endDate")),
                        "p.authorize_date", params.get("beginDate"), params.get("endDate"))
                .ge(ObjectUtils.isNotEmpty(params.get("beginDate")) && ObjectUtils.isEmpty(params.get("endDate")),"p.authorize_date", params.get("beginTime"))
                .le(ObjectUtils.isEmpty(params.get("beginDate")) && ObjectUtils.isNotEmpty(params.get("endDate")),"p.authorize_date", params.get("endTime"))
                .between(ObjectUtils.isNotEmpty(params.get("maxfee")) && ObjectUtils.isNotEmpty(params.get("minfee")),
                        "p.fee_authorize", SearchUtils.processAmount(params.get("minfee")), SearchUtils.processAmount(params.get("maxfee")))
                .ge(ObjectUtils.isNotEmpty(params.get("minfee")) && ObjectUtils.isEmpty(params.get("maxfee")),"p.fee_authorize", SearchUtils.processAmount(params.get("minfee")))
                .le(ObjectUtils.isNotEmpty(params.get("maxfee")) && ObjectUtils.isEmpty(params.get("minfee")),"p.fee_authorize", SearchUtils.processAmount(params.get("maxfee")))
                .eq(StringUtils.isNotBlank(alteration.getCheckstatus()),"b.checkstatus",alteration.getCheckstatus());

        if(StringUtils.isNotEmpty(alteration.getProjectType())){
            List<String> list = Arrays.stream(alteration.getProjectType().split(",")).collect(Collectors.toList());
            wrapper.in("p.project_type",list);
        }

        if(StringUtils.isNotEmpty(alteration.getUnitId())){
            List<String> list = Arrays.stream(alteration.getUnitId().split(",")).collect(Collectors.toList());
            wrapper.in("p.unit_id",list);
        }

        if(StringUtils.isNotEmpty(alteration.getStatus())){
            List<String> list = Arrays.stream(alteration.getStatus().split(",")).collect(Collectors.toList());
            wrapper.in("b.checkstatus",list);
        }

        //当前用户的角色
        String currentRoleKey = CurrentRoleUtils.getCurrentRoleKey();
        if (("biz_kyms").equals(currentRoleKey)) {//科研秘书 查看所属单位下的所有项目
            SysUser loginUser = SecurityUtils.getLoginUser().getUser();
            String units = loginUser.getUnitAdminScopeReal();
            if (StringUtils.isNotEmpty(units)) {
                List<String> unit = Arrays.stream(units.split(",")).collect(Collectors.toList());
                wrapper.in("p.unit_id",unit);
            }
        }

        return  wrapper;
    }


    /**
     * 检验条件
     * @param projectId
     * @return
     */
    @Override
    public String checkProject(String projectId){
        String msg = incomeService.checkProject(projectId);
        if (msg.equalsIgnoreCase("cwIncomeClaim")) {
            return "当前项目有未结束的认领经费，不能进行经费调账！";
        } else if (msg.equalsIgnoreCase( "noIncome")) {
            return "当前项目没有到账信息，不能进行经费调账！";
        }
        else if (msg.equalsIgnoreCase("alteration")) {
            return "当前项目有未结束的调账经费，不能进行经费调账！";
        } else if (msg.equalsIgnoreCase( "claimBack")) {
            return "当前项目有未结束的退回经费，不能进行经费调账！";
        } else if (msg.equalsIgnoreCase( "noProBudget")) {
            return "当前项目没有预算信息，不能进行经费调账！";
        }
        Long count =  budgetMapper.selectCount(new QueryWrapper<BizProjectFeeCardBudget>().eq(StringUtils.isNotEmpty(projectId),"PROJECT_ID",projectId));
        if (count <=0){
            return "当前项目没有可调账的科目,请检查!";
        }

//        Long count1 = claimMapper.selectCount(new QueryWrapper<BizCwIncomeClaim>()
//                .eq(StringUtils.isNotEmpty(projectId),"PROJECT_ID",projectId)
//                .eq("CHECKSTATUS",2)
//                .ne("BUDGET_SPLIT_MODDE","liuxiaoBudgetSplit"));
//        if (count1 <=0){
//            return "当前项目不可调账,请检查额度拆分方式!";
//        }
        return  msg;
    }


    /**
     * 获取页面数据
     * @param showBo
     * @return
     */
    @Override
    public BudegtAlterationVO getBudgetInfo(FundsFeeShowBo showBo){
        BudegtAlterationVO vo = new BudegtAlterationVO();
        vo.setProjectId(showBo.getProjectId());
        List<AmountAlterationVO>  alterationVOList = baseMapper.selectamountAlterationList(new QueryWrapper<BizBudgetAlteration>().eq("p.ID",showBo.getProjectId())
                .groupBy("bpi.fee_card_num,bpi.fee_charger_id,bpi.fee_charger_name,bu.name,p.id"));

        String type = "liuxiao";
        if(showBo.getProjectClass().equals(project_Class_yF)){
            type = "yfContract";
        }

        if (alterationVOList.size() >0){
            List<BudgetAmountAlterationVO>  amountAlterationVOList = baseMapper.selectbudgetAmountAlterationList(new QueryWrapper<BizBudgetAlteration>().eq("f.project_id",showBo.getProjectId())
                    .eq("f.BUDGET_TYPE",type).orderByAsc("f.subject_code"));
            List<BudgetAmountAlterationVO> treeSubjectList = buildTree(null,amountAlterationVOList);
            vo.setAmountAlterationVO(alterationVOList);
            vo.setBudgetAmountAlterationVO(treeSubjectList);
        }
        return  vo;
    }


    /**
     * 获取详情信息
     * @param showBo
     * @return
     */
    @Override
    public BudegtAlterationVO geteditInfo(FundsFeeShowBo showBo){
        BudegtAlterationVO vo = baseMapper.selectListOne(new QueryWrapper<BizBudgetAlteration>().eq("b.id",showBo.getId()));;
        List<BizFeeCardAlteration> voList = feeCardMapper.selectList(new LambdaQueryWrapper<BizFeeCardAlteration>().eq(BizFeeCardAlteration::getAlterationId,showBo.getId()));
        List<AmountAlterationVO>   voList1 = JSON.parseArray(JSON.toJSONString(voList),AmountAlterationVO.class);
        vo.setAmountAlterationVO(voList1);
        BizBudgetAlteration budgetAlteration = new BizBudgetAlteration();
        budgetAlteration.setId(showBo.getId());
        budgetAlteration.setProjectId(vo.getProjectId());
        String type = "liuxiao";
        if(vo.getProjectClass().equals(project_Class_yF)){
            type = "yfContract";
        }
        budgetAlteration.setBudgetType(type);
        List<BudgetAmountAlterationVO> amountAlterationVOList = baseMapper.selectAmountAlterationList(budgetAlteration);
        vo.setBudgetAmountAlterationVO(buildTree(null,amountAlterationVOList));
        return  vo;
    }


    /**
     * 递归构造
     * @param code
     * @param treeList
     * @return
     */
    public List<BudgetAmountAlterationVO> buildTree(String code, List<BudgetAmountAlterationVO> treeList) {
        List<BudgetAmountAlterationVO> list = treeList.stream()
                // 筛选父节点
                .filter(t -> (StringUtils.isEmpty(code)  && StringUtils.isEmpty(t.getUpCode())) || (StringUtils.isNotEmpty(code) && code.equals(t.getUpCode())))
                // 递归设置子节点
                .map(item -> {
                    item.setChildren(buildTree(item.getSubjectCode(), treeList));
                    return item;
                })
                .collect(Collectors.toList());
        return list;
    }


    /**
     * 新增
     * @param alterationVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String addBudgetAlteration(BudegtAlterationVO alterationVO) {
        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        BizBudgetAlteration alteration = new BizBudgetAlteration();
        BeanUtils.copyProperties(alterationVO,alteration);
        alteration.setAlterdate(LocalDateTime.now());
        //按钮状态点暂存:-1
        if (alterationVO.getStatus().equalsIgnoreCase("-1")){
            alteration.setCheckstatus(alterationVO.getStatus());
            alteration.setCheckdate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            alteration.setChecker(loginUser.getNickName());
        }
        Boolean flag = baseMapper.insert(alteration)>0;
        if(flag){
             flag = getaBoolean(alterationVO, alteration.getId());
        }
        String msg = flag ? null :"操作失败";
        if(StringUtils.isEmpty(msg)){
            //按钮状态为提交 1:此时角色为科研人员，调流程引擎
            if(alterationVO.getStatus().equalsIgnoreCase("1")){
                String processInstanceId = approvalApi.businessEntryApproval(alteration.getId(), modelName);
                msg = StringUtils.isEmpty(processInstanceId)?BizProcessMessages.SAVE_PARTIAL_SUCCESS:null;
            }
            //按钮状态为保存并通过 2:此时为科研管理员，直接更改数据状态为审核通过
            if(alterationVO.getStatus().equalsIgnoreCase("2")){
                updateBusinessStatus("local",alteration.getId(),alterationVO.getStatus(),loginUser.getNickName());
                updateStatus(alteration.getId(),alterationVO.getStatus(),loginUser.getNickName(),"0");
            }
        }
        return msg;
    }

    /**
     * 编辑
     * @param alterationVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String editBudgetAlteration(BudegtAlterationVO alterationVO) {
        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        BizBudgetAlteration alteration = new BizBudgetAlteration();
        BeanUtils.copyProperties(alterationVO,alteration);
        //暂存 -1
        if (alterationVO.getStatus().equalsIgnoreCase("-1")){
            //数据状态不为审核中,不更新数据状态
            if(!alterationVO.getCheckstatus().equalsIgnoreCase("1")) {
                alteration.setCheckstatus(alterationVO.getStatus());
                alteration.setCheckdate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                alteration.setChecker(loginUser.getNickName());
            }
        }
        Boolean flag = baseMapper.updateById(alteration) >0;
        if(flag){
            amountMapper.delete(new QueryWrapper<BizBudgetAmountAlteration>().eq("ALTERATION_ID",alteration.getId()));
            feeCardMapper.delete(new QueryWrapper<BizFeeCardAlteration>().eq("ALTERATION_ID",alteration.getId()));
            flag = getaBoolean(alterationVO, alteration.getId());
        }
        String msg = flag ? null :"操作失败";
        // 科研人员 1
        if(alterationVO.getStatus().equalsIgnoreCase("1")){
            String returnProcessInstanceId = approvalApi.businessEntryApproval(alterationVO.getId(), modelName);
            msg = StringUtils.isEmpty(returnProcessInstanceId)?BizProcessMessages.SAVE_PARTIAL_SUCCESS:null;
        }

        //保存并通过 2
        if(alterationVO.getStatus().equalsIgnoreCase("2")){
            //管理员的保存并通过
            if(alterationVO.getCheckstatus().equalsIgnoreCase("-1") || alterationVO.getCheckstatus().equalsIgnoreCase("3") ){
                updateBusinessStatus("local",alteration.getId(),alterationVO.getStatus(),loginUser.getNickName());
                updateStatus(alteration.getId(),alterationVO.getStatus(),loginUser.getNickName(),"0");
            }else{
                BpmTaskApproveReqVO bta = new BpmTaskApproveReqVO();
                bta.setId(alterationVO.getTaskId());
                bta.setReason(SecurityUtils.getNickName() + "保存并通过");
                flowTaskService.approveTask(SecurityUtils.getUserId(), bta);
            }
        }

        return msg;
    }

    /**
     * 写入从表数据
     * @param alterationVO
     * @param id
     * @return
     */
    private Boolean getaBoolean(BudegtAlterationVO alterationVO, String id) {
        Boolean flag = true;
        List<BizBudgetAmountAlteration> list = new ArrayList<>();
        List<AmountAlterationVO> list2 = alterationVO.getAmountAlterationVO();
        for(AmountAlterationVO alvos:list2){
            //写入biz_fee_card_alteration表
             BizFeeCardAlteration feeCardAlteration = new BizFeeCardAlteration();
             BeanUtils.copyProperties(alvos,feeCardAlteration);
             feeCardAlteration.setAlterationId(id);
             feeCardMapper.insert(feeCardAlteration);
             list = buildList(alterationVO.getBudgetAmountAlterationVO(),alvos,id);
        }
        //list 不为空时，写入biz_budget_amount_alteration表
        if(list.size() > 0) {
            flag = amountService.saveBatch(list);
        }
        return flag;
    }

    /**
     * 循环构建要保存的数据
     * @param list1
     * @param alvos
     * @param id
     * @return
     */
    public  List<BizBudgetAmountAlteration> buildList(List<BudgetAmountAlterationVO> list1,AmountAlterationVO alvos ,String id){
        List<BizBudgetAmountAlteration> list = new ArrayList<>();
        for(BudgetAmountAlterationVO vo:list1){
            for(AlterationVals vals: vo.getAlterationVals()){
                if(vals.getFeeCardNum().equals(alvos.getFeeCardNum()) && vals.getBudgetFeeChange() != null && !vals.getBudgetFeeChange().equals(BigDecimal.ZERO))
                {
                    BizBudgetAmountAlteration amountAlteration = new BizBudgetAmountAlteration();
                    BeanUtils.copyProperties(vals,amountAlteration);
                    amountAlteration.setAlterationId(id);//反写id
                    //根据经费卡号，获得经费卡负责人id
                    amountAlteration.setFeeChargerId(alvos.getFeeChargerId());
                    list.add(amountAlteration);
                }
            }
            if (!vo.getChildren().isEmpty()){
                list.addAll(buildList(vo.getChildren(),alvos,id));
            }
        }
        return  list;
    }

    /**
     * 删除
     * @param ids
     * @param isValid
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean delBudgetAlteration(Collection<String> ids, Boolean isValid){

        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        //先删从表，再删主表
        amountMapper.delete(new QueryWrapper<BizBudgetAmountAlteration>().in("ALTERATION_ID",ids));
        feeCardMapper.delete(new QueryWrapper<BizFeeCardAlteration>().in("ALTERATION_ID",ids));
        return baseMapper.deleteBatchIds(ids) >0;
    }

    private void updateStatus(String businessId, String checkStatus, String sysUserId,String processInstanceId){
        BizBudgetAlteration alteration = new BizBudgetAlteration();
        alteration.setId(businessId);
        alteration.setCheckstatus(checkStatus);
        alteration.setCheckdate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        alteration.setChecker(sysUserId);
        if(StringUtils.isNotEmpty(processInstanceId)){
            alteration.setProcessInstanceId(processInstanceId);
        }
        baseMapper.updateById(alteration);
    }

    @Override
    public void updateBusinessStatus(String tableName, String businessId, String checkStatus, String sysUserId) {
        if (StringUtils.isEmpty(tableName) || StringUtils.isEmpty(businessId) || StringUtils.isEmpty(checkStatus))
            return;
        //经费调账审核
        if ("2".equals(checkStatus)) {
            //需要写入BIZ_PROJECT_INCOME表，BIZ_PROJECT_FEE_CARD_BUDGET表

            BizProjectIncome income = baseMapper.SelectProIncome(new QueryWrapper<BizBudgetAlteration>().eq("b.id",businessId));
            //有值才插入
            if (ObjectUtils.isNotEmpty(income)){
                income.setIncomeDate(LocalDateTime.now());
                income.setCheckstatus(checkStatus);
                incomeMapper.insert(income);
                List<BizProjectFeeCardBudget> budgetList = baseMapper.SelectProFeeCardBudget(new QueryWrapper<BizBudgetAlteration>().eq("b.id",businessId));
                for(BizProjectFeeCardBudget budget:budgetList){
                    budget.setIncomeId(income.getId());
                    budgetMapper.insert(budget);
                }
            }
        }
    }
}
